package filter;

import utils.SessionVar;
import utils.DBConnection;
import utils.TextUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;

import account.Account;
import account.AccountInfo;
import examinee.Examinee;
import examinee.ExamineeInfo;
import control.ComputerInfo;
import control.Computer;
import control.ControlVar;
import exam.*;

/**
 * Created by IntelliJ IDEA.
 * User: Shawn
 * Date: 2009-5-29
 * Time: 21:28:12
 */
public class SignInFilter implements Filter {

  private static final String ERROR_CODE = "error";

  public static final int ERROR_MANAGER = 1;
  public static final int ERROR_EXAMINEE = 2;
  public static final int ERROR_TEST_DONE = 3;

  public static final String SIGNIN_MANAGER = "/manager_signin";
  public static final String SIGNIN_EXAMINEE = "/examinee_signin";

  public static final String SIGNOUT_MANAGER = "/manager_signout";
  public static final String SIGNOUT_EXAMINEE = "/examinee_signout";

  public static final String LOGIN_PAGE_MANAGER = "/index.jsp";
  public static final String LOGIN_PAGE_EXAMINEE = "/login.jsp";

  public static final String INDEX_MANAGER = "/admin/index.jsp";
  public static final String INDEX_EXAMINEE = "/exam/getTestPaper.action";

  public static final String RESOURCE_MANAGER = "/admin";
  public static final String RESOURCE_EXAMINEE = "/exam";

  public void init(FilterConfig filterConfig) throws ServletException {
  }

  public void doFilter(ServletRequest srequest, ServletResponse sresponse, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest request = (HttpServletRequest) srequest;
    HttpServletResponse response = (HttpServletResponse) sresponse;

    String uri = request.getRequestURI();
    boolean isSignInManager = uri.equals(SIGNIN_MANAGER);
    boolean isSignInExaminee = uri.equals(SIGNIN_EXAMINEE);
    boolean isSignIn = isSignInManager || isSignInExaminee;

    boolean isSignOutManager = uri.equals(SIGNOUT_MANAGER);
    boolean isSignOutExaminee = uri.equals(SIGNOUT_EXAMINEE);
    boolean isSignOut = isSignOutManager || isSignOutExaminee;

    boolean isExecutable = uri.indexOf(".jsp") != -1 || uri.indexOf(".action") != -1;
    boolean isLoginPage = uri.equals(LOGIN_PAGE_MANAGER) || uri.equals(LOGIN_PAGE_EXAMINEE);

    boolean pass = true;
    if (isSignIn) {
      pass = signin(request);
    }
    else if (isSignOut) {
      pass = signout(request);
    }
    else if (isExecutable && !isLoginPage) {
      pass = validate(request);
    }

    if (!pass) {
      int error_code = (Integer) request.getAttribute(ERROR_CODE);
      switch (error_code) {
        case ERROR_MANAGER:
          sendTopRedirect(response, LOGIN_PAGE_MANAGER + "?error=" + ERROR_MANAGER);
          break;
        case ERROR_EXAMINEE:
          sendTopRedirect(response, LOGIN_PAGE_EXAMINEE + "?error=" + ERROR_EXAMINEE);
          break;
        case ERROR_TEST_DONE:
          sendTopRedirect(response, LOGIN_PAGE_EXAMINEE + "?error=" + ERROR_TEST_DONE);
          break;
      }
      return;
    }

    if (isSignInManager) {
      response.sendRedirect(INDEX_MANAGER);
      return;
    }

    if (isSignInExaminee) {
      response.sendRedirect(INDEX_EXAMINEE);
      return;
    }

    if (isSignOutManager) {
      response.sendRedirect(LOGIN_PAGE_MANAGER);
      return;
    }

    if (isSignOutExaminee) {
      response.sendRedirect(LOGIN_PAGE_EXAMINEE);
      return;
    }

    chain.doFilter(srequest, sresponse);
  }

  private boolean validate(HttpServletRequest request) throws ServletException {
    HttpSession session = request.getSession();

    String uri = request.getRequestURI();
    boolean isManagerResource = uri.startsWith(RESOURCE_MANAGER);
    boolean isExamineeResource = uri.startsWith(RESOURCE_EXAMINEE);

    boolean isManagerLogined = isManagerResource && session.getAttribute(SessionVar.USER_ID) != null;
    boolean isExamineeLogined = isExamineeResource && session.getAttribute(SessionVar.EXAMINEE_ID) != null;

    if (isManagerResource && !isManagerLogined) request.setAttribute(ERROR_CODE, ERROR_MANAGER);
    if (isExamineeResource && !isExamineeLogined) request.setAttribute(ERROR_CODE, ERROR_EXAMINEE);

    return isManagerLogined || isExamineeLogined;
  }

  private boolean signout(HttpServletRequest request) {
    HttpSession session = request.getSession();
    session.invalidate();
    return true;
  }

  private boolean signin(HttpServletRequest request) throws ServletException {
    HttpSession session = request.getSession();
    session.invalidate();

    String uri = request.getRequestURI();
    boolean isManagerLogin = uri.equals(SIGNIN_MANAGER);
    boolean isExamineeLogin = uri.equals(SIGNIN_EXAMINEE);

    boolean signin = false;
    Connection con = new DBConnection(DBConnection.AutoCommiteOff).getConnection();

    try {
      if (isManagerLogin) signin = managerLogin(con, request);

      if (isExamineeLogin) signin = examineeLogin(con, request);

      con.commit();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
    finally {
      DBConnection.close(con);
    }

    return signin;
  }

  private boolean managerLogin(Connection con, HttpServletRequest request) throws Exception {
    HttpSession session = request.getSession();

    String account = request.getParameter("account");
    String password = request.getParameter("password");

    AccountInfo info = Account.getAccountInfo(con, account, password);
    if (info.getAid() == 0) {
      request.setAttribute(ERROR_CODE, ERROR_MANAGER);
      return false;
    }

    session.setAttribute(SessionVar.USER_ID, info.getAid());
    session.setAttribute(SessionVar.USER_NAME, info.getAname());
    session.setAttribute(SessionVar.USER_ACCOUNT, info.getAccount());
    session.setAttribute(SessionVar.USER_RIGHTS, info.getRights());
    return true;
  }

  private synchronized boolean examineeLogin(Connection con, HttpServletRequest request) throws Exception {
    HttpSession session = request.getSession();

    //computer setting
    String ip = request.getRemoteAddr();
    ComputerInfo cinfo = Computer.getComputer(con, ip);
    String zkzh = request.getParameter("zkzh");
    if (cinfo.getCid() == 0 || !cinfo.getZkzh().equals(zkzh)) {
      request.setAttribute(ERROR_CODE, ERROR_EXAMINEE);
      return false;
    }

    //examinee setting
    ExamineeInfo einfo = Examinee.getExaminee(con, zkzh, TextUtils.getZeroTime(System.currentTimeMillis()));
    if (einfo.getEid() == 0) {
      request.setAttribute(ERROR_CODE, ERROR_EXAMINEE);
      return false;
    }

    //set computer in use
    cinfo.setState(ControlVar.COMPUTER_STATE_INUSE);
    Computer.modiComputer(con, cinfo);

    //test paper
    TestPaperInfo tinfo = TestPaper.getTestPaper(con, einfo.getEid());
    if (tinfo.getTid() == 0) {
      TestPaperGenerator2 tg = new TestPaperGenerator2(con, einfo.getEid());
      tinfo = tg.generate();
      Examinee.setScore(con, einfo.getEid(), 0);
    }

    if (tinfo.getState() == ExamVar.STATE_END || tinfo.getTime() >= tinfo.getExamTime()) {
      request.setAttribute(ERROR_CODE, ERROR_TEST_DONE);
      return false;
    }

    session.setAttribute(SessionVar.EXAMINEE_ID, einfo.getEid());
    session.setAttribute(SessionVar.EXAMINEE_NAME, einfo.getEname());
    return true;
  }

  private void sendTopRedirect(HttpServletResponse response, String url) throws IOException {
    PrintWriter out = response.getWriter();
    out.println("<script>");
    out.println("top.location = '" + url + "'");
    out.println("</script>");
  }

  public void destroy() {
  }
}
